13. Exercise: Display Images in a Grid
L8 22 Displaying A Grid Of Internet Images HS-SC
Now it's your turn! If you want to start at this step, you can download this exercise from: Step.05-Exercise-Displaying-a-Grid-of-Internet-Images. You will find plenty of helpful //TODO comments there.
Your app shows you just a single property on Mars. Let's give you some real-estate choices!
When you've completed with this exercise you'll be able scroll through whole list of properties in a new RecyclerView.
- Add the Gradle dependency for the RecyclerView:
implementation "androidx.recyclerview:recyclerview:$version_recyclerview"
In
OverviewViewModelrename_propertyto_properties, and assign it aListofMarsProperty:private val _properties = MutableLiveData<List<MarsProperty>>() val properties: LiveData<List<MarsProperty>> get() = _propertiesThen update getMarsRealEstateProperties() to return the entire list instead of just one item:
_properties.value = listResult
- In
grid_view_item.xmlreplace theviewModelvariable with apropertyof typeMarsProperty:
<variable
name="property"
type="com.example.android.marsrealestate.network.MarsProperty" />
Then update the binding in mars_image to reflect the variable change:
app:imageUrl="@{property.imgSrcUrl}"
- In
OverviewFragmentinflate aFragmentOverviewBindinginstead of aGridViewItemBinding:
val binding = FragmentOverviewBinding.inflate(inflater)
- In
fragment_overview, replace theTextViewwith aRecyclerView, using aGridLayoutManagerto display items in a 2-column grid:
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/photos_grid"
android:layout_width="0dp"
android:layout_height="0dp"
android:padding="6dp"
app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:spanCount="2"
tools:itemCount="16"
tools:listitem="@layout/grid_view_item" />
Previewing the overview_fragment in the Design panel now shows a grid of images. Let's implement the RecyclerView Adapter in our app to show our list of Mars rover photos.
- In
PhotoGridAdapter.ktcreate a 'PhotoGridAdapter' class that extends aRecyclerViewListAdapterwithDiffCallback. Have it use a customPhotoGridAdapter.MarsPropertyViewHolderto present a list of<MarsProperty>objects:
class PhotoGridAdapter : ListAdapter<MarsProperty, PhotoGridAdapter.MarsPropertyViewHolder>(DiffCallback) {}
- Add the imports for the ListAdapter and MarsProperty. Make sure to import
androidx.recyclerview.widget.ListAdapter.
import androidx.recyclerview.widget.ListAdapter
import com.example.android.marsrealestate.network.MarsProperty
- Use Control-I to have Android Studio override the adapter's required
onCreateViewHolder()andonBindViewHolder()methods: Don't bother filling them out yet.
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int):
PhotoGridAdapter.MarsPropertyViewHolder {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
override fun onBindViewHolder(holder: PhotoGridAdapter.MarsPropertyViewHolder, position: Int) {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
- Create the
DiffCallbackcompanion object and override its two requiredareItemsTheSame()methods:
companion object DiffCallback : DiffUtil.ItemCallback<MarsProperty>() {
override fun areItemsTheSame(oldItem: MarsProperty, newItem: MarsProperty): Boolean {
return oldItem === newItem
}
override fun areContentsTheSame(oldItem: MarsProperty, newItem: MarsProperty): Boolean {
return oldItem.id == newItem.id
}
}
Create a
MarsPropertyViewHolderinner class, and implement thebind()method that includes a binding tomarsProperty:Hint Don't forget to call
binding.executePendingBindings()!
class MarsPropertyViewHolder(private var binding: GridViewItemBinding):
RecyclerView.ViewHolder(binding.root) {
fun bind(marsProperty: MarsProperty) {
binding.property = marsProperty
binding.executePendingBindings()
}
}
- Implement the empty
onCreateViewHolder()andonBindViewHolder()methods:
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PhotoGridAdapter.MarsPropertyViewHolder {
return MarsPropertyViewHolder(GridViewItemBinding.inflate(LayoutInflater.from(parent.context)))
}
override fun onBindViewHolder(holder: PhotoGridAdapter.MarsPropertyViewHolder, position: Int) {
val marsProperty = getItem(position)
holder.bind(marsProperty)
}
In
BindingAdapters, add abindRecyclerViewbinding adapter forlistData, and have it callsubmitList()on thePhotosGridAdapter:@BindingAdapter("listData") fun bindRecyclerView(recyclerView: RecyclerView, data: List<MarsProperty>?) { val adapter = recyclerView.adapter as PhotoGridAdapter adapter.submitList(data) }In
fragment_overview, inphotos_grid, bind thelistDatabinding adapter toviewModel.properties:
app:listData="@{viewModel.properties}"
In
OverviewFragment, set the adapter in theRecyclerView(thephotosGrid.adapterin the binding object) to a newPhotoGridAdapterbinding.photosGrid.adapter = PhotoGridAdapter()
In
fragment_overview, add an attribute to theRecyclerViewto setclipToPaddingtofalse:android:clipToPadding="false"
And, you made it! Build and run the app to see the grid of properties --- so much more choice!
If you get stuck, go back and watch the video again. Once you’re done, you can check your solution against the solution we’ve provided here: Step.05-Solution-Displaying-a-Grid-of-Internet-Images, or using this git diff.
Task Description:
Complete the tasks below to display your images in a grid.
Task Feedback:
Great job! So many properties to choose from!